package cxm.lib.speex;

public class EchoCancellation {
	static {
		System.loadLibrary("speex_jni"); // to load the libwebrtc_aecm.so library.
    }
	
	private int echoCancelState = 0;
	private int frameSize = 0;
	
	public EchoCancellation(int frameSize, int frameLength) throws SpeexException {
		if (frameSize <= 0 || frameLength <= 0)
			throw new IllegalArgumentException("size, length");
		
		this.echoCancelState = speexEchoStateInit(frameSize, frameLength);
		if (this.echoCancelState <= 0)
			throw new SpeexException("Cannot init: " + this.echoCancelState);
		this.frameSize = frameSize;
	}
	
	public void close() {
		if (this.echoCancelState <= 0)
			return;
	    speexEchoStateDestroy(this.echoCancelState);
	    this.echoCancelState = 0;
	}
	
	@Override
	protected void finalize() throws Throwable {
		super.finalize();
		if (this.echoCancelState > 0)
			this.close();
	}
	
	public void playback(short []playBuffer) {
		if (playBuffer.length != this.frameSize)
			throw new IllegalArgumentException("Buffer length");
		
		speexEchoPlayback(this.echoCancelState, playBuffer);
	}
	
	public void capture(short []inBuffer, short []outBuffer) {
		if (inBuffer.length != this.frameSize ||
				outBuffer.length != this.frameSize)
			throw new IllegalArgumentException("Frame size");
		speexEchoCapture(this.echoCancelState, inBuffer, outBuffer);
	}
	
	// return echo cancel handle
	public int getState() {
		return this.echoCancelState;
	}
	
	/* Creates a new echo canceller state    
	 * @param frame_size Number of samples to process at one time (should correspond to 10-20 ms)
	 * @param filter_length Number of samples of echo to cancel (should generally correspond to 100-500 ms)
	 * @return Newly-created echo canceller state
	 */
	private native int speexEchoStateInit(int frameSize, int frameLength);
	/* Destroys an echo canceller state 
	 * @param st Echo canceller state
	*/
	private native void speexEchoStateDestroy(int echoState);
	/* Perform echo cancellation using internal playback buffer, which is delayed by two frames
	 * to account for the delay introduced by most soundcards (but it could be off!)
	 * @param st Echo canceller state
	 * @param rec Signal from the microphone (near end + far end echo)
	 * @param out Returns near-end signal with echo removed
	*/
	private native void speexEchoCapture(int echoState, short []rec, short out[]);
	/* Let the echo canceller know that a frame was just queued to the soundcard
	 * @param st Echo canceller state
	 * @param play Signal played to the speaker (received from far end)
	*/
	private native void speexEchoPlayback(int echoState, short []play);
	/* Reset the echo canceller to its original state 
	 * @param st Echo canceller state
	 */
	private native void speexEchoReset(int echoState);
}
